package com.smart.community.work.service.impl;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smart.community.commons.cache.DataScopeInfo;
import com.smart.community.commons.exception.BusinessException;
import com.smart.community.commons.utils.FileInfoUtils;
import com.smart.community.feign.property.service.DataScopeFeign;
import com.smart.community.work.dto.LeaveQueryDTO;
import com.smart.community.work.entity.Leave;
import com.smart.community.work.mapper.LeaveMapper;
import com.smart.community.work.service.LeaveService;
import com.smart.community.work.vo.LeaveVO;

import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;

/**
 * 请假管理服务实现类
 * 
 * 严格按照《Java后端SpringBoot代码开发规范_重构版.md》Service规范实现：
 * - 继承ServiceImpl：获得基础CRUD方法
 * - 事务管理：使用@Transactional注解管理事务
 * - 异常处理：使用统一的异常处理机制
 * - 日志记录：使用@Slf4j记录关键操作日志
 * - 参数验证：进行必要的参数验证
 * - 完整注释：所有方法都有完整的JavaDoc注释
 * 
 * @author Wu.Liang
 * @since 2025-01-30
 * @version 1.0.0
 */
@Slf4j
@Service
public class LeaveServiceImpl extends ServiceImpl<LeaveMapper, Leave> implements LeaveService {

    @Resource
    private LeaveMapper leaveMapper;

    @Resource
    private DataScopeFeign dataScopeFeign;

    @Override
    @Cacheable(value = "leave", key = "'page:' + #page.current + '_' + #page.size + '_' + (#params['userId'] ?: 'null') + '_' + (#params['startDate'] ?: 'null') + '_' + (#params['endDate'] ?: 'null') + '_' + (#params['status'] ?: 'null')")
    public IPage<LeaveVO> selectLeavePage(Page<LeaveVO> page, Map<String, Object> params) throws Exception {
        log.info("分页查询请假记录，参数：{}", params);
        return leaveMapper.selectLeavePage(page, params);
    }

    @Override
    @Cacheable(value = "leave", key = "'detail:' + #id + '_' + #currentUserId")
    public LeaveVO getLeaveDetail(Long id, Long currentUserId) throws Exception {
        log.info("获取请假详情，ID：{}，当前用户ID：{}", id, currentUserId);
        
        // 参数验证
        if (id == null || id <= 0) {
            throw new BusinessException("请假记录ID必须大于0");
        }
        if (currentUserId == null || currentUserId <= 0) {
            throw new BusinessException("当前用户ID必须大于0");
        }
        
        // 获取请假详情
        LeaveVO leaveDetail = leaveMapper.selectById(id);
        if (leaveDetail == null) {
            log.warn("请假记录不存在，ID：{}", id);
            return null;
        }
        
        // 权限验证：只有申请人、审批人或管理员可以查看详情
        boolean canView = false;
        
        // 申请人可以查看自己的请假记录
        if (leaveDetail.getUserId().equals(currentUserId)) {
            canView = true;
        }
        
        // 审批人可以查看需要自己审批的请假记录
        if (leaveDetail.getApproverId() != null && leaveDetail.getApproverId().equals(currentUserId)) {
            canView = true;
        }
        
        // 管理员可以查看所有请假记录（通过数据权限控制）
        if (!canView) {
            try {
                // 检查当前用户是否有管理权限
                DataScopeInfo dataScopeInfo = dataScopeFeign.getUserDataScope(currentUserId);
                if (dataScopeInfo != null && dataScopeInfo.getPropertyCompanyIds() != null 
                    && dataScopeInfo.getPropertyCompanyIds().contains(leaveDetail.getPropertyCompanyId())) {
                    canView = true;
                }
            } catch (Exception e) {
                log.warn("检查数据权限失败，用户ID：{}，请假记录ID：{}", currentUserId, id, e);
            }
        }
        
        if (!canView) {
            log.warn("用户无权查看请假详情，用户ID：{}，请假记录ID：{}", currentUserId, id);
            return null;
        }
        
        log.info("获取请假详情成功，ID：{}", id);
        return leaveDetail;
    }

    @Override
    @Cacheable(value = "leave", key = "'user:' + #userId + '_' + (#propertyCompanyId ?: 'null')")
    public List<LeaveVO> selectByUserId(Long userId, Long propertyCompanyId) throws Exception {
        log.info("根据用户ID查询请假记录，用户ID：{}，物业公司ID：{}", userId, propertyCompanyId);
        return leaveMapper.selectByUserId(userId, propertyCompanyId);
    }

    @Override
    @Cacheable(value = "leave", key = "'pending:' + #approverId + '_' + (#propertyCompanyId ?: 'null')")
    public List<LeaveVO> selectPendingByApproverId(Long approverId, Long propertyCompanyId) throws Exception {
        log.info("根据审批人ID查询待审批请假记录，审批人ID：{}，物业公司ID：{}", approverId, propertyCompanyId);
        return leaveMapper.selectPendingByApproverId(approverId, propertyCompanyId);
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"leave"}, allEntries = true)
    public Boolean applyLeave(Leave leave) throws Exception {
        log.info("申请请假，用户ID：{}，请假类型：{}，开始日期：{}，结束日期：{}", 
                leave.getUserId(), leave.getLeaveType(), leave.getStartDate(), leave.getEndDate());
        
        // 参数验证
        if (leave.getUserId() == null) {
            throw new BusinessException("用户ID不能为空");
        }
        if (leave.getLeaveType() == null || leave.getLeaveType().trim().isEmpty()) {
            throw new BusinessException("请假类型不能为空");
        }
        if (leave.getStartDate() == null) {
            throw new BusinessException("开始日期不能为空");
        }
        if (leave.getEndDate() == null) {
            throw new BusinessException("结束日期不能为空");
        }
        if (leave.getReason() == null || leave.getReason().trim().isEmpty()) {
            throw new BusinessException("请假原因不能为空");
        }
        
        // 验证日期逻辑
        if (leave.getStartDate().isAfter(leave.getEndDate())) {
            throw new BusinessException("开始日期不能晚于结束日期");
        }
        
        // 处理附件信息 - 按照《用户上传文件功能使用指南.md》规范转换为JSON格式
        if (leave.getAttachments() != null && !leave.getAttachments().trim().isEmpty()) {
            try {
                // 验证attachments字段是否为有效的JSON格式
                if (!FileInfoUtils.isValidFileInfoJson(leave.getAttachments())) {
                    log.warn("attachments字段不是有效的JSON格式，跳过处理: {}", leave.getAttachments());
                    leave.setAttachments(null);
                } else {
                    log.info("attachments字段格式验证通过，文件数量: {}", FileInfoUtils.getFileCount(leave.getAttachments()));
                }
            } catch (Exception e) {
                log.error("处理attachments字段时发生错误: {}", e.getMessage(), e);
                leave.setAttachments(null);
            }
        }
        
        // 设置默认状态为待审批
        leave.setStatus(1); // 1-待审批
        
        // 设置物业公司ID - 从当前用户信息中获取
        if (leave.getPropertyCompanyId() == null) {
            // 这里应该从当前用户信息中获取物业公司ID
            // 暂时设置为null，后续可以通过用户服务获取
            log.warn("物业公司ID为空，请确保用户已关联物业公司");
        }
        
        // 确保所有字段都有明确的默认值，避免Seata NullPointerException
        // 这些字段在数据库中允许为NULL，但需要明确设置以避免Seata构建表记录时出错
        if (leave.getAttachmentUrl() == null) {
            leave.setAttachmentUrl(null);
        }
        if (leave.getAttachments() == null) {
            leave.setAttachments(null);
        }
        if (leave.getStartTime() == null) {
            leave.setStartTime(null);
        }
        if (leave.getEndTime() == null) {
            leave.setEndTime(null);
        }
        if (leave.getApproverId() == null) {
            leave.setApproverId(null);
        }
        if (leave.getApproveTime() == null) {
            leave.setApproveTime(null);
        }
        if (leave.getApproveRemark() == null) {
            leave.setApproveRemark(null);
        }
        if (leave.getPropertyCompanyId() == null) {
            leave.setPropertyCompanyId(null);
        }
        
        // 确保BaseEntity字段有默认值
        if (leave.getRemark() == null) {
            leave.setRemark(null);
        }
        
        return this.save(leave);
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"leave"}, allEntries = true)
    public Boolean approveLeave(Long id, Integer status, Long approverId, String approveRemark) throws Exception {
        log.info("审批请假，请假ID：{}，状态：{}，审批人ID：{}", id, status, approverId);
        
        // 参数验证
        if (id == null) {
            throw new BusinessException("请假ID不能为空");
        }
        if (status == null) {
            throw new BusinessException("审批状态不能为空");
        }
        if (approverId == null) {
            throw new BusinessException("审批人ID不能为空");
        }
        
        // 查询请假记录
        Leave leave = leaveMapper.selectOne(
            new QueryWrapper<Leave>().eq("id", id).eq("deleted", 0)
        );
        if (leave == null) {
            throw new BusinessException("请假记录不存在");
        }
        
        // 验证状态
        if (!leave.getStatus().equals(1)) {
            throw new BusinessException("该请假记录已审批，无法重复审批");
        }
        
        // 更新审批信息
        leave.setStatus(status);
        leave.setApproverId(approverId);
        leave.setApproveTime(LocalDateTime.now());
        leave.setApproveRemark(approveRemark);
        
        return this.updateById(leave);
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"leave"}, allEntries = true)
    public Boolean cancelLeave(Long id, Long userId) throws Exception {
        log.info("撤销请假申请，请假ID：{}，用户ID：{}", id, userId);
        
        // 参数验证
        if (id == null) {
            throw new BusinessException("请假ID不能为空");
        }
        if (userId == null) {
            throw new BusinessException("用户ID不能为空");
        }
        
        // 查询请假记录
        Leave leave = leaveMapper.selectOne(
            new QueryWrapper<Leave>().eq("id", id).eq("deleted", 0)
        );
        if (leave == null) {
            throw new BusinessException("请假记录不存在");
        }
        
        // 验证权限
        if (!leave.getUserId().equals(userId)) {
            throw new BusinessException("无权限撤销该请假申请");
        }
        
        // 验证状态
        if (!leave.getStatus().equals(1)) {
            throw new BusinessException("该请假记录已审批，无法撤销");
        }
        
        // 更新状态为已撤销
        leave.setStatus(4); // 4-已撤销
        
        return this.updateById(leave);
    }

    @Override
    public Map<String, Object> getLeaveStatistics(Long propertyCompanyId, LocalDate startDate, LocalDate endDate) throws Exception {
        log.info("统计请假数据，物业公司ID：{}，开始日期：{}，结束日期：{}", propertyCompanyId, startDate, endDate);
        return leaveMapper.selectLeaveStatistics(propertyCompanyId, startDate, endDate);
    }

    @Override
    public List<Map<String, Object>> getLeaveStatusStatistics(Long propertyCompanyId, LocalDate startDate, LocalDate endDate) throws Exception {
        log.info("统计各状态请假数量，物业公司ID：{}，开始日期：{}，结束日期：{}", propertyCompanyId, startDate, endDate);
        return leaveMapper.selectLeaveStatusStatistics(propertyCompanyId, startDate, endDate);
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public Boolean updateStatus(Long id, Integer status, Long updateBy) throws Exception {
        log.info("更新请假状态，请假ID：{}，状态：{}，更新人ID：{}", id, status, updateBy);
        
        // 参数验证
        if (id == null) {
            throw new BusinessException("请假ID不能为空");
        }
        if (status == null) {
            throw new BusinessException("状态不能为空");
        }
        
        Integer result = leaveMapper.updateStatus(id, status, updateBy);
        return result > 0;
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public Boolean batchUpdateStatus(List<Long> ids, Integer status, Long updateBy) throws Exception {
        log.info("批量更新请假状态，请假ID列表：{}，状态：{}，更新人ID：{}", ids, status, updateBy);
        
        // 参数验证
        if (ids == null || ids.isEmpty()) {
            throw new BusinessException("请假ID列表不能为空");
        }
        if (status == null) {
            throw new BusinessException("状态不能为空");
        }
        
        // 性能优化：批量操作，避免循环单条更新
        // 分批处理，避免单次操作数据量过大
        int batchSize = 1000;
        int totalProcessed = 0;
        
        for (int i = 0; i < ids.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, ids.size());
            List<Long> batchIds = ids.subList(i, endIndex);
            
            Integer result = leaveMapper.batchUpdateStatus(batchIds, status, updateBy);
            totalProcessed += result;
        }
        
        return totalProcessed > 0;
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public Boolean deleteById(Long id, Long updateBy) throws Exception {
        log.info("删除请假记录，请假ID：{}，更新人ID：{}", id, updateBy);
        
        // 参数验证
        if (id == null) {
            throw new BusinessException("请假ID不能为空");
        }
        
        Integer result = leaveMapper.deleteById(id, updateBy);
        return result > 0;
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public Boolean batchDelete(List<Long> ids, Long updateBy) throws Exception {
        log.info("批量删除请假记录，请假ID列表：{}，更新人ID：{}", ids, updateBy);
        
        // 参数验证
        if (ids == null || ids.isEmpty()) {
            throw new BusinessException("请假ID列表不能为空");
        }
        
        // 性能优化：批量操作，避免循环单条删除
        // 分批处理，避免单次操作数据量过大
        int batchSize = 1000;
        int totalProcessed = 0;
        
        for (int i = 0; i < ids.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, ids.size());
            List<Long> batchIds = ids.subList(i, endIndex);
            
            Integer result = leaveMapper.batchDelete(batchIds, updateBy);
            totalProcessed += result;
        }
        
        return totalProcessed > 0;
    }

    @Override
    public IPage<LeaveVO> selectLeavePageWithPermission(Page<LeaveVO> page, LeaveQueryDTO queryDTO, Long currentUserId) throws Exception {
        log.info("分页查询请假记录（支持数据权限控制），参数：{}，当前用户ID：{}", queryDTO, currentUserId);
        
        // 参数验证
        if (queryDTO == null) {
            throw new BusinessException("查询参数不能为空");
        }
        if (currentUserId == null) {
            throw new BusinessException("当前用户ID不能为空");
        }
        
        // 获取当前用户关联的物业公司ID列表
        List<Long> propertyCompanyIds = dataScopeFeign.getUserPropertyCompanyIds(currentUserId);
        log.info("用户{}关联的物业公司ID列表：{}", currentUserId, propertyCompanyIds);
        
        if (propertyCompanyIds == null || propertyCompanyIds.isEmpty()) {
            log.warn("用户{}未关联任何物业公司，尝试直接查询用户自己的请假记录", currentUserId);
            // 如果用户没有关联物业公司，直接查询用户自己的记录
            queryDTO.setUserId(currentUserId);
            return leaveMapper.selectLeavePageWithUserIds(page, queryDTO, Arrays.asList(currentUserId));
        }
        
        // 根据用户角色确定数据权限范围
        List<Long> allowedUserIds = determineAllowedUserIds(currentUserId, propertyCompanyIds);
        log.info("用户{}允许查看的用户ID列表：{}", currentUserId, allowedUserIds);
        
        // 调用Mapper查询，传入允许的用户ID列表和所有物业公司ID
        return leaveMapper.selectLeavePageWithUserIdsAndPropertyCompanies(page, queryDTO, allowedUserIds, propertyCompanyIds);
    }

    @Override
    @Cacheable(value = "leave", key = "'cleaning_staff:' + #propertyCompanyIds")
    public List<Long> getCleaningStaffUserIds(List<Long> propertyCompanyIds) throws Exception {
        log.info("查询保洁人员用户ID列表，物业公司ID列表：{}", propertyCompanyIds);
        
        if (propertyCompanyIds == null || propertyCompanyIds.isEmpty()) {
            return Collections.emptyList();
        }
        
        // 调用Mapper查询保洁人员（角色ID=17）
        return leaveMapper.getUserIdsByRoleAndPropertyCompany(17L, propertyCompanyIds);
    }

    @Override
    @Cacheable(value = "leave", key = "'security_staff:' + #propertyCompanyIds")
    public List<Long> getSecurityStaffUserIds(List<Long> propertyCompanyIds) throws Exception {
        log.info("查询安保人员用户ID列表，物业公司ID列表：{}", propertyCompanyIds);
        
        if (propertyCompanyIds == null || propertyCompanyIds.isEmpty()) {
            return Collections.emptyList();
        }
        
        // 调用Mapper查询安保人员（角色ID=5）
        return leaveMapper.getUserIdsByRoleAndPropertyCompany(5L, propertyCompanyIds);
    }

    /**
     * 根据用户角色确定允许查看的用户ID列表
     * 
     * @param currentUserId 当前用户ID
     * @param propertyCompanyIds 物业公司ID列表
     * @return 允许查看的用户ID列表
     */
    private List<Long> determineAllowedUserIds(Long currentUserId, List<Long> propertyCompanyIds) throws Exception {
        log.info("开始确定用户{}的数据权限范围，物业公司ID列表：{}", currentUserId, propertyCompanyIds);
        
        try {
            // 获取当前用户的数据权限信息
            DataScopeInfo dataScopeInfo = dataScopeFeign.getUserDataScope(currentUserId);
            if (dataScopeInfo == null) {
                log.warn("用户{}没有数据权限信息，只能查看自己的记录", currentUserId);
                return Arrays.asList(currentUserId);
            }
            
            // 检查是否为超级管理员
            Boolean isSuperAdmin = dataScopeFeign.isUserSuperAdmin(currentUserId);
            if (Boolean.TRUE.equals(isSuperAdmin)) {
                log.info("用户{}是超级管理员，可以查看所有人员请假记录", currentUserId);
                List<Long> ids = leaveMapper.getAllUserIdsByPropertyCompany(propertyCompanyIds);
                ids.add(currentUserId);
                return ids;
            }
            
            // 根据用户角色确定权限范围
            List<Long> userRoleIds = getUserRoleIdsFromDatabase(currentUserId);
            log.info("用户{}的角色ID列表：{}", currentUserId, userRoleIds);
            
            // 物业管理员（ID=9）可以查看公司内所有人员的数据
            if (userRoleIds.contains(9L)) {
                log.info("用户{}是物业管理员，可以查看所有人员请假记录", currentUserId);
                List<Long> ids = leaveMapper.getAllUserIdsByPropertyCompany(propertyCompanyIds);
                ids.add(currentUserId);
                return ids;
            }
            
            // 保洁管理（ID=18）可以查看所有保洁人员的数据
            if (userRoleIds.contains(18L)) {
                log.info("用户{}是保洁管理，可以查看保洁人员请假记录", currentUserId);
                List<Long> ids = getCleaningStaffUserIds(propertyCompanyIds);
                ids.add(currentUserId);
                return ids;
            }
            
            // 安保管理（ID=16）可以查看所有安保人员的数据
            if (userRoleIds.contains(16L)) {
                log.info("用户{}是安保管理，可以查看安保人员请假记录", currentUserId);
                List<Long> ids = getSecurityStaffUserIds(propertyCompanyIds);
                ids.add(currentUserId);
                return ids;
            }
            
            // 其他角色只能查看自己的请假记录
            log.info("用户{}是普通用户，只能查看自己的请假记录", currentUserId);
            return Arrays.asList(currentUserId);
            
        } catch (Exception e) {
            log.error("确定用户{}数据权限范围时发生异常，默认只能查看自己的记录", currentUserId, e);
            return Arrays.asList(currentUserId);
        }
    }
    
    /**
     * 从数据库查询用户角色ID列表
     * 
     * @param userId 用户ID
     * @return 角色ID列表
     */
    private List<Long> getUserRoleIdsFromDatabase(Long userId) {
        try {
            log.info("查询用户{}的角色ID列表", userId);
            List<Long> roleIds = leaveMapper.getUserRoleIds(userId);
            log.info("用户{}的角色ID列表查询结果：{}", userId, roleIds);
            return roleIds != null ? roleIds : new java.util.ArrayList<>();
        } catch (Exception e) {
            log.error("查询用户{}角色ID列表时发生异常", userId, e);
            return new java.util.ArrayList<>();
        }
    }
}